// FIT_6204_Gorodilov_GreedyView.cpp : implementation of the CFIT_6204_Gorodilov_GreedyView class
//

#include "stdafx.h"
#include "FIT_6204_Gorodilov_Greedy.h"

#include "FIT_6204_Gorodilov_GreedyDoc.h"
#include "FIT_6204_Gorodilov_GreedyView.h"
#include "FIT_6204_Gorodilov_GreedySettingsDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define POINTSIZE 10
#define HALFPOINTSIZE POINTSIZE/2

// CFIT_6204_Gorodilov_GreedyView

IMPLEMENT_DYNCREATE(CFIT_6204_Gorodilov_GreedyView, CScrollView)

BEGIN_MESSAGE_MAP(CFIT_6204_Gorodilov_GreedyView, CScrollView)
	ON_WM_ERASEBKGND()
	ON_WM_SIZE()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_RBUTTONDOWN()
	ON_UPDATE_COMMAND_UI(ID_INDICATOR_COUNT, OnUpdateCount)
	ON_COMMAND(ID_EDIT_MAKETRIANGULATION, &CFIT_6204_Gorodilov_GreedyView::OnEditMaketriangulation)
	ON_COMMAND(ID_EDIT_SHUFFLE, &CFIT_6204_Gorodilov_GreedyView::OnEditShuffle)
	ON_COMMAND(ID_EDIT_ADDPOINTS, &CFIT_6204_Gorodilov_GreedyView::OnEditAddpoints)
	ON_COMMAND(ID_EDIT_PRINTLOG, &CFIT_6204_Gorodilov_GreedyView::OnEditPrintlog)
	ON_COMMAND(ID_EDIT_SETTNGS, &CFIT_6204_Gorodilov_GreedyView::OnEditSettngs)
END_MESSAGE_MAP()

// CFIT_6204_Gorodilov_GreedyView construction/destruction

CFIT_6204_Gorodilov_GreedyView::CFIT_6204_Gorodilov_GreedyView()
: m_pDC(NULL)
, m_pBitmap(NULL)
, m_pOldBitmap(NULL)
, m_iPointFocused((UINT)-1)
, m_iPointPeeked((UINT)-1)
{
	m_pPointPen = new CPen(0, 0, RGB(0,128,255));
	m_pPointBrush = new CBrush(RGB(0,128,255));
	m_pPointBrushPeeked = new CBrush(RGB(255,0,0));
	m_pPointBrushFocused = new CBrush(RGB(0,255,255));
	m_pLinePen = new CPen(0, 0, RGB(255, 0, 55));
}

CFIT_6204_Gorodilov_GreedyView::~CFIT_6204_Gorodilov_GreedyView()
{
	if (m_pDC) {
		if (m_pOldBitmap) {
			m_pDC->SelectObject(m_pOldBitmap);
			m_pOldBitmap = NULL;
		}
		delete m_pDC;
	}
	if (m_pBitmap) {
		delete m_pBitmap;
	}
	if (m_pPointBrush) {
		delete m_pPointBrush;
	}
	if (m_pPointPen) {
		delete m_pPointPen;
	}
	if (m_pLinePen) {
		delete m_pLinePen;
	}
	if (m_pPointBrushPeeked) {
		delete m_pPointBrushPeeked;
	}
	if (m_pPointBrushFocused) {
		delete m_pPointBrushFocused;
	}
}

BOOL CFIT_6204_Gorodilov_GreedyView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CScrollView::PreCreateWindow(cs);
}

// CFIT_6204_Gorodilov_GreedyView drawing

void CFIT_6204_Gorodilov_GreedyView::OnDraw(CDC* pDC)
{
	CFIT_6204_Gorodilov_GreedyDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	CSize lScrollSize = pDoc->GetScrollSize();
	CRect clientRect;
	GetClientRect(&clientRect);
	int width = lScrollSize.cx;
	int height = lScrollSize.cy;
	if (clientRect.right - clientRect.left > width) {
		width = clientRect.right - clientRect.left;
	}
	if (clientRect.bottom - clientRect.top > height) {
		height = clientRect.bottom - clientRect.top;
	}

	m_pDC->FillSolidRect(0, 0, 
		width, height,
		RGB(50,50,50));

	m_pDC->FillSolidRect(0, 0, 
		lScrollSize.cx, lScrollSize.cy,
		RGB(250,250,210));

	CPen *pOldPen = m_pDC->SelectObject(m_pPointPen);
	CBrush *pOldBrush = m_pDC->SelectObject(m_pPointBrush);
	UINT count = pDoc->GetCount();
	for (UINT i = 0; i < count; i++) {
		CPoint point = pDoc->GetPoint(i);
		CRect rect(CPoint(point.x - HALFPOINTSIZE,
			point.y - HALFPOINTSIZE),
			CSize(POINTSIZE,POINTSIZE));
		m_pDC->Ellipse(rect);
	}
	m_pDC->SelectObject(pOldPen);
	m_pDC->SelectObject(pOldBrush);

	if (m_iPointFocused < count && 
		m_iPointPeeked >= count) {
		CPoint point = pDoc->GetPoint(m_iPointFocused);
		pOldBrush = m_pDC->SelectObject(m_pPointBrushFocused);
		CRect rect(CPoint(point.x - HALFPOINTSIZE,
			point.y - HALFPOINTSIZE),
			CSize(POINTSIZE,POINTSIZE));
		m_pDC->Ellipse(rect);
		m_pDC->SelectObject(pOldBrush);
	}

	if (m_iPointPeeked < count) {
		pOldBrush = m_pDC->SelectObject(m_pPointBrushPeeked);
		CPoint point = pDoc->GetPoint(m_iPointPeeked);
		CRect rect(CPoint(point.x - HALFPOINTSIZE,
			point.y - HALFPOINTSIZE),
			CSize(POINTSIZE,POINTSIZE));
		m_pDC->Ellipse(rect);
		m_pDC->SelectObject(pOldBrush);
	}

	pOldPen = m_pDC->SelectObject(m_pLinePen);
	if (pDoc->IsTriangulationReady()) {
		UINT count = pDoc->GetEdgesCount();
		for (UINT i = 0; i < count; i++) {
			EDGE edge1 = pDoc->GetEdge(i); 
			CPoint p1 = pDoc->GetPoint(edge1.a);
			CPoint p2 = pDoc->GetPoint(edge1.b);
			m_pDC->MoveTo(p1);
			m_pDC->LineTo(p2);
		}
	}
	m_pDC->SelectObject(pOldPen);

	pDC->BitBlt(0, 0,
		width, height,
		m_pDC,0,0,SRCCOPY);
}

void CFIT_6204_Gorodilov_GreedyView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();

	CFIT_6204_Gorodilov_GreedyDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;
	CSize lScrollSize = pDoc->GetScrollSize();

	SetScrollSizes(MM_TEXT, lScrollSize);
	if (m_pDC) {
		if (m_pOldBitmap) {
			m_pDC->SelectObject(m_pOldBitmap);
			m_pOldBitmap = NULL;
		}
		delete m_pDC;
	}
	if (m_pBitmap) {
		delete m_pBitmap;
	}

	m_pDC = new CDC();
	m_pDC->CreateCompatibleDC(GetDC());

	int width = lScrollSize.cx;
	int height = lScrollSize.cy;
	CRect clientRect;
	GetClientRect(&clientRect);
	if (clientRect.right - clientRect.left > width) {
		width = clientRect.right - clientRect.left;
	}
	if (clientRect.bottom - clientRect.top > height) {
		height = clientRect.bottom - clientRect.top;
	}
	m_pBitmap = new CBitmap();
	if (m_pBitmap->CreateCompatibleBitmap(GetDC(),
		width, height)) {
		m_pOldBitmap = m_pDC->SelectObject(m_pBitmap);
	}
}


// CFIT_6204_Gorodilov_GreedyView diagnostics

#ifdef _DEBUG
void CFIT_6204_Gorodilov_GreedyView::AssertValid() const
{
	CScrollView::AssertValid();
}

void CFIT_6204_Gorodilov_GreedyView::Dump(CDumpContext& dc) const
{
	CScrollView::Dump(dc);
}

CFIT_6204_Gorodilov_GreedyDoc* CFIT_6204_Gorodilov_GreedyView::GetDocument() const // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFIT_6204_Gorodilov_GreedyDoc)));
	return (CFIT_6204_Gorodilov_GreedyDoc*)m_pDocument;
}
#endif //_DEBUG


// CFIT_6204_Gorodilov_GreedyView message handlers

BOOL CFIT_6204_Gorodilov_GreedyView::OnEraseBkgnd(CDC* /*pDC*/)
{
	return TRUE;
}

void CFIT_6204_Gorodilov_GreedyView::OnSize(UINT nType, int cx, int cy)
{
	CScrollView::OnSize(nType, cx, cy);

	OnInitialUpdate();
}

void CFIT_6204_Gorodilov_GreedyView::OnMouseMove(UINT nFlags, CPoint point)
{
	CFIT_6204_Gorodilov_GreedyDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	bool isUpdate = false;
	m_MousePoint = point + GetScrollPosition();

	if ((MK_LBUTTON & nFlags) == MK_LBUTTON) {
		if (m_iPointPeeked < pDoc->GetCount()) {
			if (m_MousePoint.x < pDoc->GetScrollSize().cx && 
				m_MousePoint.y < pDoc->GetScrollSize().cy) { 
				pDoc->UpdatePoint(m_iPointPeeked, m_MousePoint);
			}
			isUpdate = true;
		}
	} else {
		if (m_iPointPeeked < pDoc->GetCount()) {
			isUpdate = true;
		}
		m_iPointPeeked = (UINT) -1;
	} 

	UINT iOldPoint = m_iPointFocused;
	m_iPointFocused = pDoc->PeekPoint(m_MousePoint, HALFPOINTSIZE);
	if (m_iPointFocused != iOldPoint) {
		isUpdate = true;
	}

	if (isUpdate) {
		pDoc->UpdateAllViews(NULL);
	}
	CScrollView::OnMouseMove(nFlags, point);
}

void CFIT_6204_Gorodilov_GreedyView::OnLButtonDown(UINT nFlags, CPoint point)
{
	CFIT_6204_Gorodilov_GreedyDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	m_iPointPeeked = pDoc->PeekPoint(m_MousePoint, HALFPOINTSIZE);
	if (m_iPointPeeked >= pDoc->GetCount()) {
		m_iPointPeeked = pDoc->AddPoint(point + GetScrollPosition());
	}
	pDoc->UpdateAllViews(NULL);
	
	CScrollView::OnLButtonDown(nFlags, point);
}

void CFIT_6204_Gorodilov_GreedyView::OnLButtonUp(UINT nFlags, CPoint point)
{
	m_iPointFocused = (UINT)-1;

	CScrollView::OnLButtonUp(nFlags, point);
}

void CFIT_6204_Gorodilov_GreedyView::OnRButtonDown(UINT nFlags, CPoint point)
{
	CFIT_6204_Gorodilov_GreedyDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	pDoc->DeletePoint(m_MousePoint, HALFPOINTSIZE);

	CScrollView::OnRButtonDown(nFlags, point);
}

void CFIT_6204_Gorodilov_GreedyView::OnUpdateCount(CCmdUI *pCmdUI) {
	CFIT_6204_Gorodilov_GreedyDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;
	
	CString buf;
	buf.Format("N = %d", pDoc->GetCount());
	pCmdUI->Enable();
	pCmdUI->SetText(buf);
}
void CFIT_6204_Gorodilov_GreedyView::OnEditMaketriangulation()
{
	CFIT_6204_Gorodilov_GreedyDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	DWORD systime0 = GetTickCount();
	double L = pDoc->MakeGreedyTriangulation();
	DWORD systime1 = GetTickCount();

	pDoc->UpdateAllViews(NULL);
	UINT n = pDoc->GetCount();
	double time = (systime1 - systime0) / 1000.0;
	pDoc->Log(n, L, time, 0);
	CString message; 
	message.Format("n=%d L=%lf time=%lf", n, L, time);
	MessageBox(message);
}

void CFIT_6204_Gorodilov_GreedyView::OnEditShuffle()
{
	CFIT_6204_Gorodilov_GreedyDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	UINT count = pDoc->GetCount();
	CSize scrollSize = pDoc->GetScrollSize();
	for (UINT i = 0; i < count; i++) {
		pDoc->UpdatePoint(i, CPoint(rand()%scrollSize.cx, rand()%scrollSize.cy ));
	}

	DWORD systime0 = GetTickCount();
	double L = pDoc->MakeGreedyTriangulation();
	DWORD systime1 = GetTickCount();

	pDoc->UpdateAllViews(NULL);
	UINT n = pDoc->GetCount();
	double time = (systime1 - systime0) / 1000.0;
	pDoc->Log(n, L, time, 1);
	CString message; 
	message.Format("n=%d L=%lf time=%lf", n, L, time);
	MessageBox(message);	
}

void CFIT_6204_Gorodilov_GreedyView::OnEditAddpoints()
{
	CFIT_6204_Gorodilov_GreedyDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	double time = 0;
	double L = 0.0;
	UINT n = 0;
#ifdef TESTING
	while (time < 600.0) {
		CSize scrollSize = pDoc->GetScrollSize();
		for (UINT i = 0; i < 500; i++) {
			pDoc->AddPoint(CPoint(rand()%scrollSize.cx, rand()%scrollSize.cy ));
		}

		DWORD systime0 = GetTickCount();
		L = pDoc->MakeGreedyTriangulation();
		DWORD systime1 = GetTickCount();

		pDoc->UpdateAllViews(NULL);
		time = (systime1 - systime0) / 1000.0;
		n = pDoc->GetCount();
		pDoc->Log(n, L, time, 0);

		for (int i =0; i < 2; i++) {
			CSize scrollSize = pDoc->GetScrollSize();
			for (UINT i = 0; i < n; i++) {
				pDoc->UpdatePoint(i, CPoint(rand()%scrollSize.cx, rand()%scrollSize.cy ));
			}

			DWORD systime0 = GetTickCount();
			L = pDoc->MakeGreedyTriangulation();
			DWORD systime1 = GetTickCount();
			time = (systime1 - systime0) / 1000.0;
			pDoc->Log(n, L, time, 1);
		}
		
	}
#else
	CSize scrollSize = pDoc->GetScrollSize();
	for (UINT i = 0; i < 5; i++) {
		pDoc->AddPoint(CPoint(rand()%scrollSize.cx, rand()%scrollSize.cy ));
	}

	DWORD systime0 = GetTickCount();
	L = pDoc->MakeGreedyTriangulation();
	DWORD systime1 = GetTickCount();

	pDoc->UpdateAllViews(NULL);
	time = (systime1 - systime0) / 1000.0;
	n = pDoc->GetCount();
	pDoc->Log(n, L, time, 0);
#endif

	CString message; 
	message.Format("n=%d L=%lf time=%lf", n, L, time);
	MessageBox(message);	
}

void CFIT_6204_Gorodilov_GreedyView::OnEditPrintlog()
{
	CFIT_6204_Gorodilov_GreedyDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	CFileDialog dlg(false, "txt", "log", 0, "Text files (*.txt)|*.txt|");
	if( dlg.DoModal ()==IDOK )
	{
		CString pathName = dlg.GetPathName();
		if (!pDoc->SaveLog(pathName)) {
			MessageBox("Can't save log file.");
		}
	}

}

void CFIT_6204_Gorodilov_GreedyView::OnEditSettngs()
{
	CFIT_6204_Gorodilov_GreedyDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	CSize scrollSize = pDoc->GetScrollSize();
	CFIT_6204_Gorodilov_GreedySettingsDlg dlg(this, scrollSize.cx, scrollSize.cy);
	if (IDOK == dlg.DoModal()) {
		scrollSize.cx = dlg.GetWidth();
		scrollSize.cy = dlg.GetHeight();
		pDoc->SetScrollSize(scrollSize);
		pDoc->OnNewDocument();
		OnInitialUpdate();
	}
}
